package com.songlanyun.modules.account.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.request.AlipaySystemOauthTokenRequest;
import com.alipay.api.response.AlipaySystemOauthTokenResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.songlanyun.common.enums.LockPrefixConstant;
import com.songlanyun.common.enums.MemberConstant;
import com.songlanyun.common.exception.RRException;
import com.songlanyun.common.utils.PageUtils;
import com.songlanyun.common.utils.Query;
import com.songlanyun.common.utils.RedisUtils;
import com.songlanyun.common.utils.ShareCodeUtils;
import com.songlanyun.common.utils.custom.HttpUtils;
import com.songlanyun.modules.account.dao.AccountDao;
import com.songlanyun.modules.account.entity.*;
import com.songlanyun.modules.account.model.dto.AccountDTO;
import com.songlanyun.modules.account.model.dto.ImportUserDTO;
import com.songlanyun.modules.account.model.vo.*;
import com.songlanyun.modules.account.service.*;
import com.songlanyun.modules.appconfig.entity.AppConfig;
import com.songlanyun.modules.appconfig.service.AppConfigService;
import com.songlanyun.modules.exception.MemberException;
import com.songlanyun.modules.integralrecord.service.IntegralRecordService;
import com.songlanyun.modules.pointconfig.service.PointConfigService;
import com.songlanyun.modules.shop.entity.ShopEntity;
import com.songlanyun.modules.shop.entity.ShopUserRoleConfigEntity;
import com.songlanyun.modules.shop.service.ShopService;
import com.songlanyun.modules.shop.service.ShopUserRoleConfigService;
import com.songlanyun.modules.user.exception.UserException;
import com.songlanyun.modules.user.form.MobileForm;
import com.songlanyun.modules.user.form.PasswordForm;
import com.songlanyun.modules.wechat.config.WxMaConfiguration;
import com.songlanyun.pay.common.util.AliPayManager;
import com.songlanyun.pay.configure.AliPayConfig;
import com.songlanyun.pay.configure.WxPayConfig;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.mybatis.spring.SqlSessionTemplate;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileOutputStream;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.file.Files;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;


@Service("yxtAccountService")
public class AccountServiceImpl extends ServiceImpl<AccountDao, AccountEntity> implements AccountService {

    @Resource
    private AccountService accountService;
    @Resource
    private AccountDao yxtAccountDao;
    @Resource
    private UserIdentityAssetService userIdentityAssetService;
    @Resource
    private UserThirdIdentityService userThirdIdentityService;
    @Resource
    private UserInfoService userInfoService;
    @Resource
    private ShopUserRoleConfigService shopUserRoleConfigService;
    @Resource
    private UserShopRoleService userShopRoleService;
    @Resource
    private ShopService shopService;
    @Resource
    private UserServiceAreaService userServiceAreaService;
    @Resource
    private UserServiceAreaTemporaryService userServiceAreaTemporaryService;
    @Resource
    private AppConfigService appConfigService;

    @Autowired
    private SqlSessionTemplate sqlSessionTemplate;

    @Autowired
    private PointConfigService pointConfigService;

    private final static String WX_SESSION_KEY = "WX_SESSION_KEY_";

    @Autowired
    private IntegralRecordService integralRecordService;

    @Resource
    RedisUtils redisUtils;

    //微信app id
    @Value("${wx.miniapp.configs[0].appid}")
    private String appid;

    @Value("${shop.mobile}")
    private String lrMobile;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private WxPayConfig wxPayConfig;

    @Autowired
    private AliPayConfig aliPayConfig;


    @Override
    public AccountEntity create(AccountEntity entity) {
        return null;
    }

    @Override
    public AccountEntity modify(AccountEntity entity) {
        this.baseMapper.updateById(entity);
        return entity;
    }

    @Override
    public void remove(Long id) {
    }

    @Override
    public Boolean activationUser(Long userId) {
        AccountEntity accountEntity = yxtAccountDao.selectById(userId);
        accountEntity.setActivating(true);
        accountEntity.setLastActivatingTime(new Date());
        if (yxtAccountDao.updateById(accountEntity) > 0){
            return true;
        }else {
            return false;
        }
    }

    /**
     * 列表查询
     *
     * @param params
     * @return
     */
    @Override
    public PageUtils queryPage(Map<String, Object> params) {

        IPage<AccountVO> page = null;
        String shopkeeperMonth = String.valueOf(params.get("shopkeeper_month"));
        if(StringUtils.isBlank(shopkeeperMonth) || StringUtils.equals(shopkeeperMonth, "null")) {
            page = this.baseMapper.accountPage(new Query<AccountVO>().getPage(params), params);
        } else {
            page = this.baseMapper.accountPage2(new Query<AccountVO>().getPage(params), params);
        }
        //设置其他参数
        return setOther(page, params);
    }

    @Override
    public PageUtils queryShopMemberPage(Map<String, Object> params) {
        //分页数据  -- 商家管理员
        IPage<AccountVO> page = this.baseMapper.queryShopMemberPage(new Query<AccountVO>().getPage(params), params);
        //设置其他参数
        return setOther(page, params);
    }

    @Override
    public PageUtils queryUserShopRolePage(Map<String, Object> params) {
        //分页数据  -- 商家管理员
        IPage<AccountVO> page = this.baseMapper.queryUserShopRolePage(new Query<AccountVO>().getPage(params), params);
        //设置其他参数
        return setOther(page, params);
    }

    private PageUtils setOther(IPage<AccountVO> page, Map<String, Object> params) {
        Long shopId = MapUtil.getLong(params, "shopId");
        page.getRecords().forEach(vo -> {
            setRoleAndMoney(vo, shopId);
        });

        return new PageUtils(page);
    }

    private void setRoleAndMoney(AccountVO vo, Long shopId) {
        //查询等级名称，输出商家等级输出等级名称
        String outerRoleName = shopUserRoleConfigService.getRoleNameByRoleCode(shopId, vo.getRoleCode());
        vo.setRoleName(outerRoleName);

        //如果推荐会员手机号的平台会员的，则不显示
        if (lrMobile.equals(vo.getParentUserMobile())) {
            vo.setParentUserMobile(null);
        }

        //消费金额 （会员在所有店铺的消费金额）  -- 与商家端的出入
        BigDecimal sum = BigDecimal.ZERO;
        if (shopId == null) {
            sum = userShopRoleService.getSumByUserId(vo.getId());
        } else {
            sum = userShopRoleService.getSumByUserIdAndShopId(vo.getId(), shopId);
        }
        vo.setTotalConsumptions(sum);
    }


    @Override
    public List<AccountEntity> select(Map<String, Object> params) {
        String mobile = MapUtil.getStr(params, "mobile");//手机号
//        String lockStatus = MapUtil.getStr(params, "lock_status");//锁定状态
        Integer registerSource = MapUtil.getInt(params, "register_source");//会员注册来源
        List<AccountEntity> list = this.list(
                new LambdaQueryWrapper<AccountEntity>()
                        .eq(AccountEntity::getLockStatus, false) //未锁定
                        .like(StringUtils.isNotBlank(mobile), AccountEntity::getMobile, mobile)
                        .eq(registerSource != null, AccountEntity::getRegisterSource, registerSource)
                        .orderByDesc(AccountEntity::getCreateTime)
        );

        return list;
    }


    /**
     * 保存会员信息
     *
     * @param parentAccount 推荐会员信息
     * @param dto
     */
    @Override
    @Transactional
    public Long saveAccount(AccountEntity parentAccount, AccountDTO dto) {

        //保存会员信息
        AccountEntity yxtAccountEntity = saveAccountInfo(parentAccount, dto);
        Long id = yxtAccountEntity.getId();

        //初始化会员的资产表
        UserIdentityAssetEntity userIdentityAsset = new UserIdentityAssetEntity();
        userIdentityAsset.setId(id);
        userIdentityAssetService.save(userIdentityAsset);

        //初始化会员的信息表
        UserInfoEntity userInfoEntity = new UserInfoEntity();
        userInfoEntity.setId(id);
        //如果不是微信注册，则将昵称设为手机号
        if (!MemberConstant.RegisterSource.WX.equals(dto.getRegisterSource())) {
            //注册默认生成昵称，自助生成规则为：绿马公益5960 ，即绿马公益+手机号后4位
            userInfoEntity.setNickname("会员" + dto.getMobile().substring(dto.getMobile().length() - 4));
        }
        userInfoService.save(userInfoEntity);

        //升级  -- 推荐人升级
        accountService.memberRecommendedUpgrade(parentAccount.getId());

        return id;
    }

    /**
     * //小程序注册保存信息
     *
     * @param yxtAccountEntity
     * @param yxtAccountDTO
     * @return
     */
    @Override
    @Transactional
    public Long saveWxAccount(AccountEntity yxtAccountEntity, AccountDTO yxtAccountDTO) {
        //保存会员账户、资产信息
        Long accountId = this.saveAccount(yxtAccountEntity, yxtAccountDTO);
        //保存第三方关系
        UserThirdIdentityEntity identityEntity = new UserThirdIdentityEntity();
        identityEntity.setIdentityCode(yxtAccountDTO.getOpenId());//
        identityEntity.setUserId(accountId);//会员用户id
        userThirdIdentityService.save(identityEntity);
        return accountId;
    }

    /**
     * 修改密码
     *
     * @param account
     * @param password
     * @param newPassword
     * @return
     */
    @Override
    public void updatePass(AccountEntity account, String password, String newPassword) {

        String passwordEnc = "";
        if (StringUtils.isNotBlank(password)) {
            passwordEnc = new Sha256Hash(password, account.getSalt()).toHex();
        }
        //sha256加密
        String newPasswordEnc = new Sha256Hash(newPassword, account.getSalt()).toHex();

        boolean flag = this.update(
                new LambdaUpdateWrapper<AccountEntity>()
                        .eq(AccountEntity::getId, account.getId())
                        .eq(StringUtils.isNotBlank(password), AccountEntity::getPassword, passwordEnc)
                        .set(AccountEntity::getPassword, newPasswordEnc)
        );

        if (!flag) {
            throw new RRException(UserException.ORIGINAL_PASSWORD_ERROR);
        }
    }

    @Override
    public void updateMobile(AccountEntity account, String mobile, String newMobile, String invitationCode) {
        boolean flag = this.update(
                new LambdaUpdateWrapper<AccountEntity>()
                        .eq(AccountEntity::getId, account.getId())
                        .eq(AccountEntity::getMobile, mobile)
                        .set(AccountEntity::getMobile, newMobile)
                        .set(AccountEntity::getInvitationCode, invitationCode)
        );

        if (!flag) {
            throw new RRException(UserException.MOBILE_INCORRECTNESS);
        }
    }

    /**
     * 根据openid获取会员信息
     *
     * @param openId
     * @return
     */
    @Override
    public AccountEntity getAccountByOpenId(String openId) {
        AccountEntity account = yxtAccountDao.getAccountByOpenId(openId);

        return account;
    }

    @Override
    public AccountEntity getByMobile(String mobile) {
        AccountEntity entity = yxtAccountDao.selectOne(
                new LambdaQueryWrapper<AccountEntity>()
                        .eq(AccountEntity::getMobile, mobile)
                        .last("limit 1")
        );

        if (entity != null) {
            //用户已锁定
            isLock(entity.getLockStatus());
        }
        return entity;
    }

    @Override
    public AccountEntity getByCode(String invitationCode) {
        return yxtAccountDao.selectOne(
                new LambdaQueryWrapper<AccountEntity>()
                        .eq(AccountEntity::getInvitationCode, invitationCode)
                        .last("limit 1")
        );
    }

    /**
     * 保存注册信息 并返回用户id
     *
     * @param accountDTO
     * @param accountM
     * @return
     */
    @Override
    @Transactional
    public Long WxRegister(AccountDTO accountDTO, AccountEntity accountM) {
        //该用户是第一次注册，没有在APP上注册过，保存会员账户、资产信息
        if (accountM == null) {
            //根据邀请码查询商家
            String invitationCode = accountDTO.getInvitationCode();
            AccountEntity accountEntity = disposeCode(invitationCode);

            //小程序第一次注册保存信息
            accountDTO.setRegisterSource(MemberConstant.RegisterSource.WX);//会员注册来源
            return this.saveWxAccount(accountEntity, accountDTO);
        } else {
            //保存过手机，判断是否绑定过openid
            UserThirdIdentityEntity entity = userThirdIdentityService.getOne(
                    new LambdaQueryWrapper<UserThirdIdentityEntity>()
                            .eq(UserThirdIdentityEntity::getThirdType, MemberConstant.ThirdType.WECHAT)
                            .eq(UserThirdIdentityEntity::getUserId, accountM.getId())
            );
            //没有绑定过，则已经在APP注册过，保存第三方记录即可，邀请码作废
            if (entity == null) {
                //保存第三方关系
                UserThirdIdentityEntity identityEntity = new UserThirdIdentityEntity();
                identityEntity.setIdentityCode(accountDTO.getOpenId());//
                identityEntity.setUserId(accountM.getId());//会员用户id
                userThirdIdentityService.save(identityEntity);
            } else {
                //绑定过，则是该手机已经绑定过别的openid，需报错
                throw new RRException(MemberException.USER_IS_BINDING.getMsg());
            }
            return accountM.getId();
        }

    }

    /**
     * 查询查询会员升级商家下的隶属会员
     *
     * @param parentPath
     * @param subjectionShopId
     * @return
     */
    @Override
    public List<Long> getSubordinate(String parentPath, Long subjectionShopId) {
        List<Long> ids = yxtAccountDao.getSubordinate(parentPath, subjectionShopId);
        if (ids == null) {
            return new ArrayList<Long>();
        }
        return ids;
    }

    /**
     * 修改这些会员的会员表中的隶属商家
     *
     * @param accountList
     * @param shopId
     */
    @Override
    public void updateByShopId(List<Long> accountList, Long shopId) {
        accountList.forEach(v -> {
            AccountEntity accountEntity = yxtAccountDao.selectById(v);
            accountEntity.setSubjectionShopId(shopId);
            yxtAccountDao.updateById(accountEntity);
        });
    }

    @Override
    public AccountEntity getUserById(Long userId, Boolean tw) {
        AccountEntity obj = this.getById(userId);
        if (obj == null) {
            if (tw) {
                throw new RRException(MemberException.NOT_EXISTS);
            }
        }
        return obj;
    }

    @Override
    public AccountInfoVO getAllById(Long id, Long shopId) {

        AccountInfoVO vo = this.baseMapper.getAllById(id);
        //用户其他角色
        //查询是否是商家
        ShopEntity shop = shopService.getShopByUserId(id,false);
        List<Integer> role = new ArrayList<>();
        if (vo.getIsCelebrity()) {//1网红身份
            role.add(1);
        }
        if (shop != null) {
            //属于商家 0商家
            role.add(0);
            vo.setShopMobile(shop.getMobile());
            vo.setLogo(shop.getLogo());
        }
        vo.setRoleList(role);
        //邀请人 -- 根据邀请码查询
        AccountEntity entity = this.baseMapper.selectById(vo.getParentUserId());
        if (ObjectUtil.isNotNull(entity)) {
            UserInfoEntity userInfo = this.baseMapper.getUserInfoByCode(entity.getInvitationCode());
            if (ObjectUtil.isNotNull(userInfo)) {
                AccountVO accountInfo = this.baseMapper.getAccountInfo(userInfo.getId());
                String invited = StringUtils.isNotBlank(userInfo.getRealName()) ? userInfo.getRealName() : userInfo.getNickname();
                invited =  String.format("%s(%s)",invited,accountInfo.getMobile());
                vo.setInvited(invited);
            }
        }

        //下级用户
        List<AccountDownVO> accountDownVOS = this.baseMapper.getDownById(id);
//        accountDownVOS.forEach(a -> {
//            //设置商家输出等级
//            String outerRoleName = shopUserRoleConfigService.getRoleNameByRoleCode(shopId, a.getRoleCode());
//            a.setRoleName(outerRoleName);
//        });

        vo.setAccountDownVOS(accountDownVOS);
        return vo;
    }

    /**
     * 会员消费到达 -- 升级
     *
     * @param userId 会员id
     * @param shopId 店铺id
     * @param amount 消费金额
     */
    @Override
    @Transactional
    public void memberConsumeUpgrade(Long userId, Long shopId, BigDecimal amount) {

        //1、查询会员在当前店铺的总消费,并增加金额
        UserShopRoleEntity userShopRole = userShopRoleService.updateAmount(userId, shopId, amount);

        //2、查询该会员的消费额在当前店铺应该在哪个等级
        ShopUserRoleConfigEntity shopUserRoleConfigEntity = shopUserRoleConfigService.getByThresholdCompare(shopId, userShopRole.getTotalConsumption());

        //3、对比等级，如果会员等级小于该消费额该有的等级，则升级
        compareLevel(userShopRole, shopUserRoleConfigEntity, shopId, userId);

    }

    /**
     * 会员推荐人数到达 -- 升级
     * 会员注册时，会员的推荐人数达到后，该会员在该直属店铺升级
     *
     * @param userId 推荐人id
     */
    @Override
//    @Transactional
    public void memberRecommendedUpgrade(Long userId) {

        //1、查询该会员推荐的总人数
        Long num = getNumByUserId(userId);

        //查询该用户的隶属店铺id
        Long shopId = this.getSubjectionShopId(userId);
        //2、查询该会员的推荐总人数在直属店铺应该在哪个级别
        ShopUserRoleConfigEntity shopUserRoleConfigEntity = shopUserRoleConfigService.getByNumCompare(shopId, num);

        //查询该用户在当前店铺的等级
        UserShopRoleEntity userShopRole = userShopRoleService.getUserShopRole(shopId, userId);
        //3、对比等级，如果会员等级小于该推荐人数该有的等级，则升级
        compareLevel(userShopRole, shopUserRoleConfigEntity, shopId, userId);

    }

    /**
     * 比较会员等级与店铺配置等级，小于则升级
     *
     * @param userShopRole
     * @param shopUserRoleConfigEntity
     */
    private void compareLevel(UserShopRoleEntity userShopRole, ShopUserRoleConfigEntity shopUserRoleConfigEntity, Long shopId, Long userId) {
        if (userShopRole != null) {//会员等级配置存在时，直接比较
            if (userShopRole.getLevel() < shopUserRoleConfigEntity.getLevel()) {
                userShopRoleService.updateLevelByUserAndShop(userId, shopId, shopUserRoleConfigEntity.getLevel());
            }
        } else {//会员等级配置不存在时，初始化一条记录在比较
            if (ObjectUtil.isNull(shopUserRoleConfigEntity)) {
                throw new RRException("商家等级配置设置错误，请联系管理员");
            }
            if (0 < shopUserRoleConfigEntity.getLevel()) {
                UserShopRoleEntity init = userShopRoleService.init(userId, shopId, shopUserRoleConfigEntity.getLevel(), BigDecimal.ZERO);

                userShopRoleService.updateById(init);
            }
        }
    }

    @Override
    public void updateStatus(Long id, Boolean lock_status) {
        AccountEntity entity = yxtAccountDao.selectById(id);
        entity.setLockStatus(lock_status);
        yxtAccountDao.updateById(entity);
    }

    @Override
    public void updateOflineShopownerStatus(Long id, Integer oflineShopowner) {
        AccountEntity entity = yxtAccountDao.selectById(id);
        entity.setOflineShopowner(oflineShopowner);
        yxtAccountDao.updateById(entity);
    }

    @Override
    public String getMobileByUserId(Long userId) {
        AccountEntity entity = yxtAccountDao.selectById(userId);
        if (entity != null) {
            return entity.getMobile();
        }
        return null;
    }

    @Override
    public Long getSubjectionShopId(Long userId) {
        AccountEntity entity = yxtAccountDao.selectById(userId);
        if (entity != null) {
            return entity.getSubjectionShopId();
        }
        return null;
    }

    @Override
    /**
     * 获取openid
     *
     * @param param
     * @return
     */
    public String getOpenId(Map<String, Object> param) {
        String code = String.valueOf(param.get("code"));

        if (StringUtils.isBlank(code)) {
            return null;
        }
        final WxMaService wxService = WxMaConfiguration.getMaService(appid);

        try {
            WxMaJscode2SessionResult session = wxService.getUserService().getSessionInfo(code);
            String openid = session.getOpenid();
            String sessionKey = session.getSessionKey();
            redisUtils.set(WX_SESSION_KEY + openid, sessionKey);

            return openid;
        } catch (WxErrorException e) {
            log.error(e.getMessage(), e);
        }

        return null;
    }

    /**
     * 小程序获取OpenId和SessionKey
     *
     * @param param
     * @return
     */
    @Override
    public Map<String, String> getOpenIdAndSessionKey(Map<String, Object> param) {
        String code = String.valueOf(param.get("code"));

        if (StringUtils.isBlank(code)) {
            return null;
        }
        final WxMaService wxService = WxMaConfiguration.getMaService(appid);

        try {
            WxMaJscode2SessionResult session = wxService.getUserService().getSessionInfo(code);
            //TODO 可以增加自己的逻辑，关联业务相关数据
            Map<String, String> hashMap = new HashMap<>();
            hashMap.put("openId", session.getOpenid());
            hashMap.put("sessionKey", session.getSessionKey());
            redisUtils.set(WX_SESSION_KEY + session.getOpenid(), session.getSessionKey());
            return hashMap;
        } catch (WxErrorException e) {
            log.error(e.getMessage(), e);
        }

        return null;
    }

    @Override
    public String getWxMobile(Map<String, Object> param) {
        String openId = String.valueOf(param.get("openId"));

        String sessionKey = redisUtils.get(WX_SESSION_KEY + openId);
        String encryptedData = String.valueOf(param.get("encryptedData"));
        String ivStr = String.valueOf(param.get("iv"));
        final WxMaService wxService = WxMaConfiguration.getMaService(appid);

        WxMaPhoneNumberInfo phoneNoInfo = wxService.getUserService().getPhoneNoInfo(sessionKey, encryptedData, ivStr);
        return phoneNoInfo.getPhoneNumber();
    }

    @Override
    public String getCodeById(Long id) {
        AccountEntity accountEntity = this.baseMapper.selectById(id);
        if (accountEntity != null) {
            return accountEntity.getInvitationCode();
        }
        return null;
    }

    @Override
    public byte[] getWxCode(String scene) {

        final WxMaService wxService = WxMaConfiguration.getMaService(appid);
        byte[] bytes = new byte[0];
        try {
            File file = wxService.getQrcodeService().createWxaCodeUnlimit(scene, "pages/index/index");
            bytes = Files.readAllBytes(file.toPath());

            FileOutputStream fos = new FileOutputStream("C:/Users/EDZ/Desktop/MyNotes/cc/code2.jpg");
            fos.write(bytes);
            fos.close();

        } catch (Exception e) {

            e.printStackTrace();
        }

        return bytes;
    }

    @Override
    public void lastLoginTime(Long id) {
        this.baseMapper.lastLoginTime(id);
    }

    @Override
    public List<AccountParentVO> getAllParentUser(Long userId) {

        AccountEntity account = this.baseMapper.selectById(userId);
        if (account != null) {
            //查询所有父级会员
            List<Long> parentPathArr = account.getParentPathArr();
            if (parentPathArr.size() > 0) {
                return this.baseMapper.getAllParentUser(parentPathArr);
            }
        }

        return new ArrayList<>();
    }
    @Override
    public List<AccountParentVO> getAllLevelUpParentUser(Long userId) {

        AccountEntity account = this.baseMapper.selectById(userId);
        if (account != null) {
            //查询所有父级会员
            List<Long> parentPathArr = account.getParentPathArr();
            parentPathArr.add(userId);
            if (parentPathArr.size() > 0) {
                return this.baseMapper.getAllParentUser(parentPathArr);
            }
        }

        return new ArrayList<>();
    }

    @Override
    public List<AccountParentVO> getAllParentUserAndLevel(Long userId, Long shopId) {
        AccountEntity account = this.baseMapper.selectById(userId);
        if (account != null) {
            //查询所有父级会员 及 店铺等级
            List<Long> parentPathArr = account.getParentPathArr();
            if (parentPathArr.size() > 0) {
                List<AccountParentVO> vos = this.baseMapper.getAllParentUserAndLevel(parentPathArr, shopId);
                //设置商家输出等级
                vos.forEach(a -> {
                    String outerRoleName = shopUserRoleConfigService.getRoleNameByRoleCode(shopId, a.getRoleCode());
                    a.setRoleName(outerRoleName);
                });
                return vos;
            }
        }

        return new ArrayList<>();
    }

    @Override
    public AccountVO getAccountInfo(Long userId) {
        AccountVO info = this.baseMapper.getAccountInfo(userId);
        return info;
    }

    @Override
    public AccountVO getAccountSubInfo(Long userId, Long shopId) {
        AccountVO info = this.baseMapper.getAccountInfo(userId);
        //设置商家输出等级名称
        AccountVO shopAccountInfo = getShopAccountInfo(userId, shopId);
//        String outerRoleName = shopUserRoleConfigService.getRoleNameByRoleCode(shopId, shopAccountInfo.getRoleCode());
        info.setRoleName(shopAccountInfo.getRoleName());
        UserIdentityAssetEntity userIdentityAsset = userIdentityAssetService.getById(userId, false);
        info.setVoucher(userIdentityAsset.getVoucher());
        return info;
    }

    @Override
    public List<AccountDownVO> myPartner(Long userId) {
        List<AccountDownVO> vos = this.baseMapper.getDownById(userId);
        return vos;
    }

    @Override
    public int myPartnerNum(Long userId) {
        return this.baseMapper.myPartnerNum(userId);
    }

    @Override
    public AccountVO getShopAccountInfo(Long userId, Long shopId) {
        AccountVO info = this.baseMapper.getShopAccountInfo(userId, shopId);
        //设置商家输出等级名称
        String outerRoleName = shopUserRoleConfigService.getRoleNameByRoleCode(shopId, info.getRoleCode());
        info.setRoleName(outerRoleName);
        return info;
    }

    @Override
    public AccountAppVO appAccountInfo(Long userId) {
        return this.baseMapper.appAccountInfo(userId);
    }

    @Override
    public String getQrcodeByCode(String code) {
        AccountEntity entity = this.baseMapper.selectOne(
                new LambdaQueryWrapper<AccountEntity>()
                        .eq(AccountEntity::getInvitationCode, code)
        );
        if (entity != null) {
            return entity.getQrcode();
        }
        return null;
    }

    @Override
    public void saveQrcode(AccountEntity account) {
        this.baseMapper.saveQrcode(account);
    }

    @Override
    @Transactional
    public void batchImport(List<ImportUserDTO> list, Long ptShopId, Long ptUserId) {

        //会员信息
        this.baseMapper.saveAll(list, ptShopId, ptUserId);
        //个人信息

        //个人资产信息

        //会员等级信息


    }

    @Override
    public List<AccountExportVO> exportList(Map<String, Object> params) {
        IPage<AccountVO> page = null;

        //数据 -- 平台管理员
        List<AccountExportVO> list = null;
        String shopkeeperMonth = String.valueOf(params.get("shopkeeper_month"));
        if(StringUtils.isBlank(shopkeeperMonth) || StringUtils.equals(shopkeeperMonth, "null")) {
            list = this.baseMapper.exportList(params);
        } else {
            list = this.baseMapper.exportList2(params);
        }
        return list;
    }

    @Override
    public List<AccountVO> shopMemberExportList(Map<String, Object> params) {
        //数据 -- 平台管理员
        List<AccountVO> list = this.baseMapper.shopMemberExportList(params);
        setOtherByList(list, params);
        return list;
    }


    @Override
    @Transactional
    public void updateGrade(AccountEntity account, Function<Object, Object> callBack) {
        RLock lock = redissonClient.getLock(LockPrefixConstant.UPDATE_MEMBER_GRADE + account.getId());
        lock.lock(2, TimeUnit.SECONDS);

        try {
            Long id = account.getId();
            Long parentUserId = account.getParentUserId();//推荐人
            //如果推荐人不存在，则无需处理
            AccountEntity parentUser = this.getById(parentUserId);
            if (parentUser == null) {
                throw new RRException(MemberException.REFERRER_NOT_EXIST);
            }
            //如果推荐人没有改变，则无需处理
            AccountEntity a = this.getUserById(id, true);
            if (parentUserId.equals(a.getParentUserId())) {
                throw new RRException(MemberException.REFERRER_NOT_CHANGE);
            }
            //如果推荐人是下面的会员，则不让修改
            if (isBelongOwn(a, parentUser)) {
                throw new RRException(MemberException.REFERRER_NOT_DOWN);
            }
            //如果推荐人被禁用，则不让修改
            if (parentUser.getLockStatus()) {
                throw new RRException(MemberException.REFERRER_DISABLED);
            }

            //1、改变推荐人：改变该会员的推荐人
            a.setParentUserId(account.getParentUserId());
            this.baseMapper.updateById(a);

            //2、改变ID链：查询该会员和其下所有人，改变ID链
            updateParentPath(a, parentUser);

            //3、改变隶属商家
            updateSubShop(a, parentUser);

            //4、保存敏感日志
            String name1 = userInfoService.getNameById(id);//会员
            String name2 = userInfoService.getNameById(parentUserId);//推荐会员
            String remark = String.format("将会员【%s】挪到会员【%s】下", name1, name2);
            if (callBack != null) {
                callBack.apply(remark);
            }
        } finally {
            lock.unlock();
        }

    }

    @Override
    public void forgetPass(PasswordForm form) {
        //根据手机号查询会员
        AccountEntity account = accountService.getByMobile(form.getMobile());
        if (account == null) {
            throw new RRException(MemberException.NOT_EXISTS);
        }
        //更新密码
        accountService.updatePass(account, form.getPassword(), form.getNewPassword());

    }

    @Override
    public void changeMobile(MobileForm form, Long userId) {
        //检验新手机号是否已注册
        accountService.verifyMobile(form.getNewMobile());
        //会员信息
        AccountEntity account = accountService.getUserById(userId, true);
        //校验原手机号和密码
//        checkMobileAndPass(account, form.getMobile(), form.getPassword());

        //更新手机号  -- 需要将邀请码也要更新掉
        accountService.updateMobile(account, form.getMobile(), form.getNewMobile(),
                ShareCodeUtils.idToCode(Long.parseLong(form.getNewMobile())));

    }

    private void checkMobileAndPass(AccountEntity account, String mobile, String password) {
        if (!account.getMobile().equals(mobile)) {
            //原手机号不正确
            throw new RRException(UserException.MOBILE_INCORRECTNESS);
        }
        //sha256加密
        String passwordEnc = new Sha256Hash(password, account.getSalt()).toHex();

        if (!account.getPassword().equals(passwordEnc)) {
            //原密码不正确
            throw new RRException(UserException.PASSWORD_INCORRECTNESS);
        }

    }

    @Override
    public AccountEntity platformCode() {
        return this.baseMapper.selectOne(
                new LambdaQueryWrapper<AccountEntity>()
                        .eq(AccountEntity::getParentUserId, 0)
                        .last("limit 1")
        );
    }

    @Override
    public List<Long> getAllMemberId() {
        return this.baseMapper.getAllMemberId();
    }

    @Override
    public AccountAppVO appInfo(Long userId) {
        ShopEntity shopEntity = shopService.selectPlatformShop();
        Long shopId = 0L;
        if (shopEntity != null) {
            shopId = shopEntity.getId();
        }
        return this.baseMapper.appInfo(userId, shopId);
    }

    @Override
    public Integer memberStatistics(Long shopId, Integer type) {
        return this.baseMapper.selectMemberNum(shopId, type);
    }

    /**
     * 处理邀请码
     */
    @Override
    public AccountEntity disposeCode(String invitationCode) {
        AccountEntity invitationAccount = new AccountEntity();
        //邀请码为空时，改为平台邀请码
        if (StringUtils.isBlank(invitationCode)) {
            invitationAccount = accountService.platformCode();
        } else {
            invitationAccount = accountService.getByCode(invitationCode);//推荐会员信息
        }
        if (invitationAccount == null) {
            throw new RRException(MemberException.CODE_NOT_EXIST.getMsg());
        }

        return invitationAccount;
    }


    private boolean isBelongOwn(AccountEntity account, AccountEntity parentUser) {
        //查询该会员下所有会员ID
        String parentPath = account.getParentPath() + account.getId() + ",";
        List<Long> ids = this.baseMapper.listByParentPath(parentPath);

        return ids.contains(parentUser.getId());
    }

    private void updateSubShop(AccountEntity account, AccountEntity parentUser) {
        //没有修改之前的隶属商家
        Long subjectionShopId = account.getSubjectionShopId();
        //判断该会员是否是商家
        //(1)是：那下面会员不用改
        if (!shopService.isShopByAccountId(account.getId(),false)) {
            //查询下面所有与自己隶属商家一样的会员,商家除外
            List<Long> ids = getSubordinateIds(account);
            ids.add(account.getId());//添加自己
            //(2)不是：查询需改变后的隶属商家
            Long shopId = getShopIdByParentUser(parentUser);

            if (shopId != null) {
                //批量修改隶属商家ID
                this.baseMapper.updateSubShopIdByIds(ids, shopId);
                //TODO 拷贝会员等级：查询在之前商家的会员等级，拷贝一份过来，将金额重置
                //此处先写逻辑，后面需跟产品协商，只有此处可能需要拷贝等级
                //该会员有可能在之前商家有过记录
                userShopRoleService.saveAndUpdateByIdsAndShop(ids, subjectionShopId, shopId);

            }


        }
    }

    private Long getShopIdByParentUser(AccountEntity parentUser) {
        Long shopId;
        // 判断推荐人是否是商家
        if (shopService.isShopByAccountId(parentUser.getId(),false)) {
            //①是：改变下面会员的隶属商家为推荐人商家
            shopId = shopService.getShopIdByUserId(parentUser.getId(), false);
        } else {
            //②不是：改变下面会员的隶属商家为推荐人的隶属商家
            shopId = parentUser.getSubjectionShopId();
        }
        return shopId;
    }

    private List<Long> getSubordinateIds(AccountEntity account) {
        String parentPath = account.getParentPath() + account.getId() + ",";
        Long subjectionShopId = account.getSubjectionShopId();
        return getSubordinate(parentPath, subjectionShopId);
    }

    private void updateParentPath(AccountEntity account, AccountEntity parentUser) {
        String parentPath = account.getParentPath() + account.getId() + ",";//推荐    ,1,1097,1099, + 1101,
        String NewParentPath = parentUser.getParentPath() + parentUser.getId() + ",";//,1,1097,1099, + 1102,
        //查询会员下所有会员
        List<AccountEntity> list = this.baseMapper.selectList(
                new LambdaQueryWrapper<AccountEntity>()
                        .like(AccountEntity::getParentPath, parentPath)
        );
        list.add(account);//加上自己

        //改变ID链
        list.forEach(a -> {
            String path = a.getParentPath();//,1,1097,1099,1101,
            if (StringUtils.isNotBlank(path)) {
                //,1,1097,1099,1101,   ,1,1097,1099,  -> ,1,1097,1099,1102,
                String replace = path.replace(account.getParentPath(), NewParentPath);
                a.setParentPath(replace);
                this.baseMapper.updateById(a);
            }
        });

        //数据库修改下级路径
//        this.baseMapper.replaceParentPath(parentPath, account.getParentPath(), NewParentPath);

    }


    private void setOtherByList(List<AccountVO> list, Map<String, Object> params) {
        //设置其他参数
        Long shopId = MapUtil.getLong(params, "shopId");
        list.forEach(a -> {
            a.loadParentUser();
            setRoleAndMoney(a, shopId);
        });
    }


    /**
     * 查询该会员推荐的总人数
     *
     * @return
     */
    private Long getNumByUserId(Long userId) {

        return yxtAccountDao.getNumByUserId(userId);

    }

    /**
     * 保存会员
     *
     * @param parentAccount 推荐会员信息
     * @param dto
     * @return
     */
    private AccountEntity saveAccountInfo(AccountEntity parentAccount, AccountDTO dto) {
        AccountEntity account = new AccountEntity();
        //保存密码时加密
        String password = dto.getPassword();
        if (StringUtils.isBlank(password)) {
            password = dto.getMobile();
        }
        //sha256加密
        account.passwordEn(password);
        account.setParentUserId(parentAccount.getId());//推荐用户Id(父级id)

        //如果上级会员是商家，则隶属商家是上级商家
        ShopEntity shop = shopService.getShopByUserId(parentAccount.getId(), false);
        if (shop != null) {
            account.setSubjectionShopId(shop.getId());
        } else {
            //隶属那个商家Id(还是account),赋值上级隶属商家
            account.setSubjectionShopId(parentAccount.getSubjectionShopId());
        }

        String parentPath = parentAccount.getParentPath() + parentAccount.getId() + ",";
        account.setParentPath(parentPath);//设置上级路径

        String mobile = dto.getMobile();

        account.setMobile(mobile);//手机号
        //生成邀请码
        String invitationCode = ShareCodeUtils.idToCode(Long.parseLong(mobile));
        account.setInvitationCode(invitationCode);//邀请码
        account.setRegisterSource(dto.getRegisterSource());//会员注册来源
        account.setRegisterTime(new Date());//会员注册来源
        //保存会员账号表
        AccountEntity accountEntity = accountService.getByCode(invitationCode);
        if (ObjectUtil.isNotNull(accountEntity)) {
            throw new RRException(MemberException.CODE_EXIST);
        }

        yxtAccountDao.insert(account);
        return account;
    }

    /**
     * 用户锁定
     *
     * @param LockStatus
     */
    private void isLock(boolean LockStatus) {
        if (LockStatus) {
            throw new RRException(MemberException.USER_DISABLED);
        }
    }

    @Override
    public void verifyMobile(String newMobile) {
        Integer count = this.baseMapper.selectCount(
                new LambdaQueryWrapper<AccountEntity>()
                        .eq(AccountEntity::getMobile, newMobile)
        );

        if (count > 0) {
            throw new RRException(MemberException.NEW_PHONE_IS_REGISTER);
        }
    }


    @Override
    public OperatingCenterVO operatingCenterInfo(Long userId) {
        OperatingCenterVO vo = this.baseMapper.operatingCenterInfo(userId);
        if (StringUtils.isEmpty(vo.getInvited())) {
            vo.setInvited(vo.getInvitedNickname());
        }

//        if(vo.getActivating())
//        {
//            PointConfig config = pointConfigService.loadConfig(true);
//            Date lastActivatingTime = vo.getLastActivatingTime();
//            Date date1 = DateUtils.addDateDays(lastActivatingTime, config.getActivationPeriodDay());
//            if(date1.compareTo(new Date())<=0)
//            {
//                AccountEntity entity = this.getUserById(userId, true);
//                //激活过期要修改激活状态
//                entity.setActivating(false);
//                accountService.modify(entity);
//                vo.setActivating(false);
//                vo.setNoActivatingDayNum(-1);
//            }
//            else {
//                Long between = DateUtil.between(lastActivatingTime, new Date(), DateUnit.DAY);
//                vo.setNoActivatingDayNum(config.getActivationPeriodDay() - between.intValue());
//            }
//        }
        return vo;
    }

//    public static void main(String[] args) {
//        Date s =  DateUtil.parse("2023-03-26 11:58","yyyy-MM-dd HH:mm");
//        System.out.println(s.compareTo(new Date()));
//        Long between = DateUtil.between(s, new Date(), DateUnit.DAY);
//        System.out.println(between);
//    }


    @Override
    public String getWechatOpenIdByCode(String code) {
        if (StringUtils.isBlank(code)) {
            throw new RRException("请求参数code不能为空");
        }
        //微信开放平台
        try {
            String url = String.format("https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code",
                    wxPayConfig.getAppId(), wxPayConfig.getAppSecret(), code);
            HttpResponse httpResponse = HttpUtils.doGet(url, null, new HashMap<>(), null);
            HttpEntity httpEntity = httpResponse.getEntity();
            String tokens = EntityUtils.toString(httpEntity, "utf-8");
            JSONObject object = JSONObject.parseObject(tokens);
//            log.debug(String.format("request accessToken success. [result={%s}]", object));
            if (ObjectUtil.isNotNull(object.getInteger("errcode")) && object.getInteger("errcode") == 40029) {
                throw new RRException("请求参数code错误");
            }
            String openid = object.getString("openid").replaceAll("\"", "");
            if (StringUtils.isBlank(openid)) {
                throw new RRException("获取微信唯一标识异常");
            }
//            redisUtils.set(RedisKeys.getWxAppToken(openid), openid);
            return openid;
        } catch (Exception ex) {
            throw new RRException("获取微信唯一标识异常");
        }
    }

    @Override
    public String getAlipayUserIdByCode(String code) {
        //使用支付宝小程序的固定方法获取auth_code
        if (code == null || code.length() == 0) {
            throw new RRException("请求参数code不能为空");
        } else {
            //String serverUrl, String appId, String privateKey, String format,String charset, String alipayPublicKey, String signType
            //实例化客户端 参数：正式环境URL,Appid,商户私钥 PKCS8格式,字符编码格式,字符格式,支付宝公钥,签名方式
            AlipayClient alipayCertClient = AliPayManager.createAlipayCertClient(aliPayConfig);

            AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest();
            // 值为authorization_code时，代表用code换取
            request.setGrantType("authorization_code");
            //授权码，用户对应用授权后得到的
            request.setCode(code);
            //这里使用execute方法
            AlipaySystemOauthTokenResponse response = null;
            try {
                response = alipayCertClient.certificateExecute(request);
                //刷新令牌，上次换取访问令牌时得到。见出参的refresh_token字段
                request.setRefreshToken(response.getAccessToken());
                //返回成功时 就将唯一标识返回
                if (response.isSuccess()) {
                    log.debug("调用成功");
                    return response.getUserId();
                } else {
                    throw new RRException("调用失败");
                }
            } catch (AlipayApiException e) {
                throw new RRException("获取支付宝唯一标识异常");
            }
        }
    }

    @Override
    public CenterSettingVO centerSettingInfo(Long userId, Integer number) {
        CenterSettingVO vo = this.baseMapper.centerSettingInfo(userId);
        if (ObjectUtil.isNull(number)) {
            number = 0;
        }
        //当前版本号
        AppConfig appConfig = appConfigService.getOne();
        if (ObjectUtil.isNotNull(appConfig)) {
            if (appConfig.getNumber() > number) {
                vo.setCheckLatestVer(true);
            }
            vo.setVer(appConfig.getVer());
        }
        return vo;
    }

    @Override
    public AccountParentVO loadByArea(MemberConstant.AreaType areaType, String code) {
        //根据地区查询用户
        return this.baseMapper.selectOneByArea(areaType.getCode(), code);
    }


    @Override
    public AliPayConfig getConfig() {
        return aliPayConfig;
    }

    @Override
    public Integer getAllActivatingCount(Long userId) {
        return this.baseMapper.getAllActivatingCount(userId);
    }

    @Override
    public List<AccountEntity> getAllActivatingUsers() {
        return this.baseMapper.getAllActivatingUsers();
    }

    @Override
    public Integer getChildActivatingCount(Long userId) {
        return this.baseMapper.getChildActivatingCount(userId);
    }

    @Override
    public AccountAppVO getByShareCode(String invitationCode) {
        return this.baseMapper.getByShareCode(invitationCode);
    }

    @Override
    public List<Long> getDownAllUserIds(Long userId) {
        return this.baseMapper.getDownAllUserIds(userId);
    }

    @Override
    public void updateAccountAddress(Long userId, String accountAddress) {
        AccountEntity account = new AccountEntity();
        account.setId(userId);
        account.setAccountAddress(accountAddress);
        account.setActivating(null);
        account.setGrade(null);
        this.updateById(account);
    }

    @Override
    public List<AccountEntity> getNullAccoutAddressUsers(Integer limit) {
        return this.baseMapper.getNullAccoutAddressUsers(limit);
    }

    @Override
    public List<HashMap<String,Object>> updateTeamLevel(){
        List<HashMap<String,Object>> list = this.baseMapper.updateTeamLevelSelect();
        return list;
    }
    @Override
    public void updateGradeById(List<HashMap<String,Object>> list){
        int c = 0;
        for(HashMap<String,Object> info:list){
            String id = info.get("id").toString();
//            System.out.println(info.get("id"));
//            System.out.println(id);
//            System.out.println("--------------");
            Integer teamCount = this.baseMapper.selectTeamById(id);
//            System.out.println("id:"+id+"*** teamCount:"+teamCount);
            if(teamCount >= 29){
                Integer res = this.baseMapper.updateUserGrade(Integer.valueOf(id));
                if(res < 1){
                    System.out.println("错误"+id);
                }
            }
        }
        System.out.println(c+"---------------------------");
    }

    @Override
    public List<AccountEntity> selectUserAdvList(Integer seeTimesOneDay) {
        List<AccountEntity> accountEntityList = yxtAccountDao.selectList(new QueryWrapper<AccountEntity>()
                .eq("see_times", seeTimesOneDay));
        return accountEntityList;
    }

    @Override
    public List<AccountEntity> getUserInviteList(Long userId){
        List<AccountEntity> list = this.baseMapper.selectUserInviteByUserId(userId);
        return list;
    }
}
